/**
 * Created by hongto on 2016/8/11.
 */

(function () {

  var zIndex = 0;

  function topZindex () {
    return zIndex++;
  }

  var gutils = {
    /**
     * 通过得到对象的rect.
     * left top 是绝对的.只要统一在一个坐标系里面就好了
     */
    getRect: function (dom) {
      return dom.getBoundingClientRect();
    },
    concatRect: function (rects) {
      if (!_.isArray(rects)) {
        rects = [ rects ];
      }
      var left = _(rects).map(function (r) {
          return r.left;
        }).min() || 0;
      var top = _(rects).map(function (r) {
          return r.top;
        }).min() || 0;
      var right = _(rects).map(function (r) {
          return r.right;
        }).max() || 0;
      var bottom = _(rects).map(function (r) {
          return r.bottom;
        }).max() || 0;
      var width = right - left;
      var height = bottom - top;
      return {
        left: left,
        right: right,
        top: top,
        bottom: bottom,
        width: width,
        height: height
      }
    },
    /**
     * 用jquery修订了偏差的值
     */
    getFixedRect: function (selector) {
      var $dom = $(selector);
      if ($dom.length) {
        var width = $dom.width();
        var height = $dom.height();
        var offset = $dom.offset();
        return {
          left: offset.left,
          right: offset.left + width,
          top: offset.top,
          bottom: offset.top + height,
          width: width,
          height: height
        }
      }
      return null;
    },
    getRelativeXY: function (x1, y1, x2, y2) {
      return {
        x: x2 - x1,
        y: y2 - y1
      }
    },
    /**
     *  用jquery 修订了偏差的相对值
     */
    getRelativeRect: function (relativeSelector, selector) {
      var $relativeSelector = $(relativeSelector);
      var $selector = $(selector);
      var relativeOffset = $relativeSelector.offset();
      var offset = $selector.offset();
      var width = $selector.width();
      var height = $selector.height();

      var left = offset.left - relativeOffset.left;
      var top = offset.top - relativeOffset.top;
      return {
        left: left,
        right: left + width,
        top: top,
        bottom: top + height,
        width: width,
        height: height
      }
    },
    getUnionRect: function (root, dom) {

    },
    /**
     * rect2 是不是完成在rect1 当中
     * @param rect1
     * @param rect2
     */
    allIn: function (rect1, rect2) {
    },
    // 是不是相交
    intersectRect: function (r1, r2) {
      return !(r2.left > r1.right ||
      r2.right < r1.left ||
      r2.top > r1.bottom ||
      r2.bottom < r1.top);
    },
    contains: function ($parent, $el) {
      return jQuery.contains($parent.tagName && $parent || $parent[ 0 ]
        , $el.tagName && $el || $el[ 0 ]);
    },
    getPointRect: function (x, y) {
      return {
        left: x,
        right: x + 1,
        top: y,
        bottom: y + 1,
        width: 1,
        height: 1
      }
    }
  }

  var csses = {
    dragHandle: "can-drag-handle",
    root: "lan-root",
    currentSelected: "lan-current-selected",
    selectSection: "lan-select-section",
    canDrop: "can-drop",
    hide: "lan-hide",
    zone: "lan-zone",
    comp: "lan-comp",
    compSelected: "lan-comp-selected",
    container: "lan-container"
  };

  var snap = {
    x: 17,
    y: 17,
    getX: function (x) {
      return snap.x * x;
    },
    getY: function (y) {
      return snap.y * y;
    },
    getRow: function (x) {
      return Math.floor(x / snap.x);
    },
    getCol: function (y) {
      return Math.floor(y / snap.y);
    }
  };

  // 初始化.el是装载点.其他dom都是通过model再自动生成的
  function born (el, model, options) {
    // 树形缓存
    var treePrefix = "tree_"
    var treeCache = {};

    // 全局的状态
    var states = {};

    // 某个item的状态
    var item_states = {
      // 正常状态
      normal: "",
      // 在选区状态
      selection: "lan-selection",
      // 被选择状态,
      selected: "lan-selected"
    };

    var baseModel = {
      $$parentModel: undefined,
      $$api: undefined,
      sizeX: 0,
      sizeY: 0,
      layout: undefined,
      selected: false

    };

    var baseController = {
      $dom: undefined,
      model: undefined,
      isRoot: function () {
        return this.model === rootModel;
      },
      append: function (models) {
        if (!_.isArray(models)) {
          models = [ models ];
        }
        var pm = this.model;
        var components = this.model.components;
        _.each(models, function (model) {
          loadModel(model, pm)
          components.push(model);
        })

      },
      parentModel: function () {
        return this.model.$$parentModel;
      },
      isInTheCurrentSection: function () {
        return this.$dom.parent()[ 0 ] === $currentSelected[ 0 ];
        return gutils.contains($currentSelected, this.$dom);
      },
      // 这个只是对象初始化.并不是注入初始化
      init: function () {
      },
      remove: function () {
      },
      isSelected: function () {
        return this.model.selected;
      },
      isInSection: function () {

      },
      addToSection: function () {
      },
      select: function () {
        this.model.selected = true;
        this.$dom.addClass(csses.compSelected);
      },
      unSelect: function () {
        this.model.selected = false;
        this.$dom.removeClass(csses.compSelected);
      },
      syncDom: function () {
        var me = this;
        var parentModel = this.model.$$parentModel;
        var $parent = parentModel.$$api.$dom;
        if ($parent[ 0 ] != me.$dom.parent()[ 0 ]) {
          var bodyOffset = me.$dom.offset();
          var targetOffset = $parent.offset();

          // todo bug 大概错了1像素

          me.$dom.css({
            //zIndex: topZindex(),
            left: bodyOffset.left - targetOffset.left,
            top: bodyOffset.top - targetOffset.top
          });
          //setTimeout(function () {
          $parent.append(me.$dom.detach());
        }
      },
      setParent: function (parentModel, syncDom) {
        var me = this;

        var oldParent = this.model.$$parentModel;
        if (oldParent === parentModel) {
          if (syncDom === true) {
            me.syncDom();
          }

          return;
        }
        // 清理工作
        if (oldParent) {
          var oldParentController = oldParent.$$api;
          if (oldParentController) {
            _.remove(oldParentController.model.components, this.model);
          }
        }
        this.model.$$parentModel = parentModel;
        parentModel.components.push(this.model);

        if (syncDom === true) {
          me.syncDom();
        }

      },
      onLayout: function () {
      },
      // 将视图的结构同步到状态上面去
      sync: function () {

      }
    }

    // 通过一个$dom 得到相对的left top
    function getRelative ($dom) {
      var offset = $dom.offset();
      var xy = gutils.getRelativeXY(rootOffset.left, rootOffset.top, offset.left, offset.top);
      return {
        left: xy.x,
        top: xy.y
      }
    }

    var $$selection;

    var selectionStart = undefined;

    function doStartSelection (pageX, pageY, comp) {
      selectionStart = {
        pageX: pageX,
        pageY: pageY,
        // 当前选中的容器
        currentStartContainer: comp
      };
      var xy = gutils.getRelativeXY(rootOffset.left, rootOffset.top, pageX, pageY);
      selectionStart.x = xy.x;
      selectionStart.y = xy.y;
      $$selection.css({
        left: selectionStart.x,
        top: selectionStart.y,
        width: 0,
        height: 0
      })
    }

    //初始化选区
    function initSelection () {
      // todo bug 拖动异常

      $root.on("mousemove", function (e) {
        if (e.which != 1) {
          return;
        }
        if (selectionStart) {
          var width = e.pageX - selectionStart.pageX;
          var height = e.pageY - selectionStart.pageY;
          $$selection.show().css("transform-origin", "left top");

          if (width >= 0) {
            if (height >= 0) {
              $$selection.css("transform", "rotateY(0deg)");
            } else {
              $$selection.css("transform", "rotateY(0deg) rotateX(180deg)");
            }
          } else {
            if (height >= 0) {
              $$selection.css("transform", "rotateY(180deg) rotateX(0deg)");
            } else {
              $$selection.css("transform", "rotateY(180deg) rotateX(180deg)");
            }
          }
          $$selection.css({
            width: Math.abs(width),
            height: Math.abs(height)
          });

        } else {

        }
      });

      $("body").on("mouseup", function (e) {
        if (selectionStart) {
          var startModel = selectionStart.currentStartContainer.$$api.model;

          var containers = startModel.components;
          var rect = gutils.getRect($$selection[ 0 ]);
          var needAddToSection = _(containers).filter(function (itemModel) {
            return gutils.intersectRect(rect, gutils.getRect(itemModel.$$api.$dom[ 0 ]));
          }).map(function (itemModel) {
            return itemModel.$$api;
          }).value();
          createSelection(needAddToSection);
          $currentSelected.show();
        }

        $$selection.hide();
        selectionStart = undefined;
      })

    }

    // 是某个元素变成可以拖动
    // 并且这个元素在拖动完成的时候能放到对的位置
    // 需要维护状态.如进入,选中.点击和开始需要区分开
    var dragStart = undefined;

    function drag (controller, $drag) {
      var $dom = controller.$dom;
      var model = controller.model;

      var dom = $dom[ 0 ];

      // 点击
      if (model.container) {
        $drag.on("mousedown", handerSelect);
      } else {
        $dom.on("mousedown", handerSelect);
      }
      $dom.on("mousedown", handerSelection);

      function handerSelection (e) {
        if (model.container) {
          doStartSelection(e.pageX, e.pageY, model);
        }
      }

      function handerSelect (e) {
        if (controller.isRoot()) {
          return;
        }
        if (controller.isInTheCurrentSection()) {
          // 激活选区
          $currentSelected.show();
          $currentSelected.find(">." + csses.comp).each(function () {
            this.$$api.unSelect();
          })
        } else {
          addSelection(controller, e.ctrlKey);
        }
        controller.select();
        $currentSelected.show();
        //if (model.container) {
        //
        //} else {
        startDrag(e.pageX, e.pageY);
        //}

        e.stopPropagation();

        return false;
      }

    }

    function isInTheCurrentSection ($dom) {
      return gutils.contains($currentSelected, $dom);
    }

    function startDrag (pageX, pageY) {
      var position = $currentSelected.position();
      var containers = findNotSelectedContainers();
      dragStart = {
        containers: containers,
        startDom: $currentSelected[ 0 ],
        left: position.left,
        top: position.top,
        pageX: pageX,
        pageY: pageY
      }
    }

    function dragMove () {

      $currentSelected.on("mousedown", function (e) {
        syncSelectionDom();
        $currentSelected.hide();
        //putBack();
      })

      $(document).on("mousemove", function (e) {

        //e.stopPropagation();
        if (dragStart) {
          var $dom = $currentSelected;
          var dx = (e.pageX - dragStart.pageX);
          var dy = (e.pageY - dragStart.pageY);
          var left = dragStart.left + dx;
          var top = dragStart.top + dy;
          $dom.css({
            left: left,
            top: top
          });
          findSelectionsTheRightContainer(dragStart.containers);
        } else {
        }
        return false;
      });

      function putBack () {
        if (dragStart) {
          calcRightModel();
          _.each(findAllContainers(), function (c) {
            c.$$api.$dom.removeClass(csses.canDrop);
          })
        }
        dragStart = undefined;
      }

      $(document).on("mouseup", function (e) {
        putBack();
        return;

      })
    }

    function findSelectionsTheRightContainer (containers) {
      var rs = [];
      $currentSelected.find(">." + csses.comp).each(function () {
        var $dom = $(this);
        var offset = $dom.offset();
        var topContainer = findTheRightContainer(containers, offset.left, offset.top);
        if (topContainer) {
          rs.push(topContainer);
        }
      })
      _.each(containers, function (c) {
        if (_.includes(rs, c)) {
          c.$$api.$dom.addClass(csses.canDrop);
        } else {
          c.$$api.$dom.removeClass(csses.canDrop);
        }
      })

      return rs;
    }

    // 模型采用装载模式
    function loadModel (model, parentModel, options) {
      var $dom = $("<div>").addClass(csses.comp);
      if (model.container) {
        $dom.addClass(csses.container);
      }

      model = _.defaults(model, baseModel, {
        $$parentModel: parentModel
      });
      var controller = _.assign({}, baseController, {
        $dom: $dom,
        model: model
      });
      $dom[ 0 ].$$api = controller;
      model.$$api = controller;

      // 通过配置信息,初始化一些位置信息
      var realW = snap.getX(model.sizeX);
      var realH = snap.getX(model.sizeY);
      $dom.css({
        zIndex: topZindex(),
        left: snap.getX(model.col || 0),
        top: snap.getX(model.row || 0),
        width: realW,
        height: realH
      });
      var $drag = $dom;
      if (model.container && parentModel) {
        $drag = $("<div>").addClass(csses.dragHandle).text("移动");
        $dom.append($drag);
      }
      //加入到dom树上面
      if (parentModel) {
        var $parentDom = parentModel.$$api.$dom;
        $parentDom.append($dom);
      } else {

      }
      drag(controller, $drag);

      var components = model.components;
      if (components) {
        _.each(components, function (component) {
          loadModel(component, model, options);
        });
      } else {
        if (model.container) {
          model.components = [];
        }
      }

      return model;
    }

    // 所有的容器
    function findAllContainers () {
      return $body.find("." + csses.container).map(function (i, itemDom) {
        return itemDom.$$api.model;
      })
    }

    function findNotSelectedContainers () {
      var rs = _($root.find("." + csses.container)).map(function (itemDom) {
        return itemDom.$$api.model;
      }).value();
      rs.push(rootModel);
      return rs;
    }

    //最适合的容器
    function findTheRightContainer (containers, pageX, pageY) {
      var rect = gutils.getPointRect(pageX, pageY);
      var rs = _(containers).filter(function (item) {
        var $dom = item.$$api.$dom;
        if ($dom.hasClass("." + csses.hide)) {
          return false;
        }
        var dom = $dom[ 0 ];
        var itemRect = gutils.getRect(dom);
        if (gutils.intersectRect(rect, itemRect)) {
          return true;
        } else {
          return false;
        }
      }).value();
      var tops = [];
      var nos = [];
      _.each(rs, function (item) {
        var parentModel = item.$$api.parentModel();
        while (parentModel && _.includes(rs, parentModel) && !_.includes(nos, parentModel)) {
          nos.push(parentModel);
          parentModel = parentModel.$$api.parentModel();
        }
      })
      _.pullAll(rs, nos);
      return _.maxBy(rs, function (item) {
        return item.$$api.$dom.css("zIndex") * 1;
      });

    }

    function syncSelectionDom () {
      $currentSelected.find(">." + csses.comp).each(function () {
        this.$$api.syncDom();
        this.$$api.unSelect();
      });
    }

    function createSelection (controllers) {
      var rs = _.map(controllers, function (controller) {
        return {
          rect: gutils.getRelativeRect($body, controller.$dom),
          controller: controller
        };
      });

      syncSelectionDom();
      var maxRect = gutils.concatRect(_.map(rs, "rect"));

      $currentSelected.css({
        left: maxRect.left,
        top: maxRect.top,
        width: maxRect.width + 1,
        height: maxRect.height + 1
      });
      _.each(rs, function (item) {
        var relativeRect = item.rect;
        var controller = item.controller;
        controller.$dom.css({
          left: relativeRect.left - maxRect.left,
          top: relativeRect.top - maxRect.top
        });
        $currentSelected.append(controller.$dom);
      })
    }

    function putDomToSelection (controller) {
      if (!gutils.contains($currentSelected, controller.$dom)) {
        var relativeRects = getSelectionRelativeRects();
        var relativeRect = gutils.getRelativeRect($body, controller.$dom);

        relativeRects.push(relativeRect);

        // 计算大矩形
        var maxRect = gutils.concatRect(relativeRects);

        $currentSelected.css({
          left: maxRect.left,
          top: maxRect.top,
          width: maxRect.width,
          height: maxRect.height
        });
        controller.$dom.css({
          left: relativeRect.left - maxRect.left,
          top: relativeRect.top - maxRect.top
        });

        $currentSelected.append(controller.$dom);
      }
      //var comps = $currentSelected.find(">." + csses.comp);

    }

    function removeDomToTheRightPlace (controller, containers) {
      var $dom = controller.$dom;

      var offset = gutils.getRect($dom[ 0 ]);
      var rc_top = findTheRightContainer(containers, offset.left, offset.top);

      if (rc_top) {
        controller.setParent(rc_top.$$api.model);
      } else {
        //超出边界情况
      }

      //rc_list.max;

    }

    function getSelectionRelativeRects () {
      var comps = $currentSelected.find(">." + csses.comp);
      var relativeRects = _.map(comps, function (comp) {
          return gutils.getRelativeRect($body, comp);
        }) || [];
      return relativeRects;
    }

    // 加入到选区
    function addSelection (controller, append) {
      if (append === true) {
        putDomToSelection(controller);
      } else {
        calcRightModel();
        syncSelectionDom();
        putDomToSelection(controller);
      }
    }

    function calcRightModel () {
      var comps = $currentSelected.find(">." + csses.comp);

      var containers = findNotSelectedContainers();

      comps.each(function () {
        //this.$$api.unSelect();
        removeDomToTheRightPlace(this.$$api, containers);
      });
    }

    function applyDomChangeByModel () {}

    // 从选区清除
    function clearSelection (items) {
    }

    // 清除所有的选区
    function clearAllSelection () {
    }

    //移动某个item,真正实现的时候需要剔除祖先已经存在的.
    function moveItem (items, dx, dy) {
    }

    // 删除items
    function removeItems (items) {
    }

    // 放下item ,并放在合适的位置上.需要考虑贴合的问题
    function putItems (items) {
    }

    // 决定将一个外源的item 放到画布上面
    function put (pageX, pageY, putFn) {
    }

    function midAlign () {
      var top = $currentSelected.height() / 2;
      $currentSelected.find(">." + csses.comp).each(function () {
        var $this = $(this);
        var thisH = $this.height() / 2;
        $this.css("top", top - thisH);
      });
    }

    // 左对齐
    function leftAlign () {
      $currentSelected.find(">." + csses.comp).css({
        left: 0
      });
    }

    // 右对齐
    function rightAlign () {
      var width = $currentSelected.width();
      $currentSelected.find(">." + csses.comp).each(function () {
        var $this = $(this);
        $this.css("left", width - $this.width());
      });
    }

    function createHelperLine () {

    }

    function removeHelperLine () {

    }

    function syncBodySize () {
      $body.width($root.width()).height($root.height());
    }

    // 最外面的
    var $el = $(el);

    var $body = $("<div>").css({
      position: "relative"
    });
    // body 保证内部的布局正常
    $el.append($body);

    var rootModel = loadModel(model, undefined, options);
    var $root = rootModel.$$api.$dom.addClass(csses.root);
    // 加入body
    $body.append($root);
    // 加入选择区的dom
    $$selection = $("<div>").css({
      position: "absolute"
    }).addClass(csses.selectSection).hide();
    $body.append($$selection);

    // $root 的兄弟
    $currentSelected = $("<div>").css({
      position: "absolute",
      left: 0,
      top: 0
    }).addClass(csses.currentSelected).hide();

    $body.append($currentSelected);

    syncBodySize();

    //初始化选区的逻辑
    initSelection();

    // 初始化拖动事件
    dragMove();

    var rootOffset = $root.offset();
    var rootRect = gutils.getFixedRect($root);

    var api = {
      dragging: function (selector, putFn) {
        var $$doc = $(document.body);
        var bodyOffset = $$doc.offset();
        $(selector).each(function () {
          var $this = $(this);
          $this.on("mousedown", function (e) {
            var offset = $this.offset();
            //offset.left = offset.left - bodyOffset.left;
            //offset.top = offset.top - bodyOffset.top;
            var $clone = $this.clone();
            $$doc.append($clone)
            //debugger;
            $clone.css({
              position: "absolute",
              width: $this.width(),
              height: $this.height()
            });
            $clone.offset(offset);
            var start = {
              pageX: e.pageX,
              pageY: e.pageY
            };
            var containers = findAllContainers();
            var moveFn = function (e) {
              var left = offset.left + e.pageX - start.pageX;
              var top = offset.top + e.pageY - start.pageY;
              $clone.offset({
                left: left,
                top: top
              });

              var topRc = findTheRightContainer(containers, left, top);
              _.each(containers, function (c) {
                if (topRc == c) {
                  c.$$api.$dom.addClass(csses.canDrop);
                } else {
                  c.$$api.$dom.removeClass(csses.canDrop);
                }
              })
            }
            $(document).on("mousemove", moveFn);
            var mouseUpFn = function (e) {
              var coffset = $clone.offset();

              var bodyOffset = $body.offset();

              var left = coffset.left - bodyOffset.left;
              var top = coffset.top - bodyOffset.top;

              if (_.isFunction(putFn)) {
                var topRc = findTheRightContainer(findAllContainers(), coffset.left, coffset.top);
                if (topRc) {
                  var topRcOffset = topRc.$$api.$dom.offset();

                  var relativeLeft = coffset.left - topRcOffset.left;
                  var relativeTop = coffset.top - topRcOffset.top;
                  putFn(topRc, {
                    row: snap.getRow(relativeTop),
                    col: snap.getCol(relativeLeft)
                  }, function (model) {
                    topRc.$$api.append(model);
                  }, $this);
                } else {
                  console.warn("没有找到合适的放置位置");
                }
              }
              $body.find("." + csses.container).removeClass(csses.canDrop);
              $clone.remove();
              start = undefined;
              $(document).off("mousemove", moveFn);
              $(document).off("mouseup", mouseUpFn);

            }
            $(document).on("mouseup", mouseUpFn)

          })
        })
      },
      leftAlign: leftAlign,
      rightAlign: rightAlign,
      midAlign: midAlign,
      rootModel: rootModel,
      currentSelection: undefined,
      utils: {
        setContainer: function (selector, isContainer) {
          var $el = $(selector);
          if (isContainer) {
            $el.addClass(csses.container);
          } else {
            $el.removeClass(csses.container);
          }
        },
        show: function (selector) {
          var $el = $(selector);
          $el.removeClass(csses.hide);
        },
        hide: function (selector) {
          var $el = $(selector);
          $el.addClass(csses.hide);
        }
      }
    };

    return api;
  }

  // test

  var cs = {
    container: true,
    sizeX: 20,
    sizeY: 30,
    components: [ {
      container: true,
      row: 2,
      col: 2,
      sizeX: 10,
      sizeY: 10,
      components: [ {
        row: 1,
        col: 1,
        sizeX: 4,
        sizeY: 4
      } ]
    } ]
  }

  for (var i = 0; i < 100; i++) {
    cs.components.push({
      container: true,
      row: 15,
      col: 2,
      sizeX: 8,
      sizeY: 8
    });
  }

  var api = born("#root", {
    // 第一层次默认
    container: true,
    sizeX: 50,
    sizeY: 40,
    components: [ cs, {
      row: 20,
      col: 35,
      sizeX: 3,
      sizeY: 3
    }, {
      row: 10,
      col: 25,
      sizeX: 6,
      sizeY: 6
    } ]
  });

  $(function () {
    $("[ref=leftAlign]").click(function () {
      api.leftAlign();
    })

    $("[ref=rightAlign]").click(function () {
      api.rightAlign();
    })

    $("[ref=midAlign]").click(function () {
      api.midAlign();
    })

    api.dragging(".controls [ref]", function (topRc, position, append, $this) {
      var ref = $this.attr("ref");

      var execs = {
        label: function () {
          var model = {
            row: position.row,
            col: position.col,
            sizeX: 3,
            sizeY: 4
          }
          append(model);
        },
        container: function () {
          append({
            container: true,
            row: position.row,
            col: position.col,
            sizeX: 8,
            sizeY: 8
          });
        },
        tab_layout: function () {
          append({
            container: true,
            row: position.row,
            col: position.col,
            sizeX: 8,
            sizeY: 8,
            components: [ {
              container: true,
              row: 2,
              col: 0,
              sizeX: 8,
              sizeY: 6
            }, {
              container: true,
              row: 2,
              col: 0,
              sizeX: 8,
              sizeY: 6
            }, {
              container: true,
              row: 2,
              col: 0,
              sizeX: 8,
              sizeY: 6
            }, {
              container: true,
              row: 2,
              col: 0,
              sizeX: 8,
              sizeY: 6
            } ]
          });
        }
      }
      if (execs[ ref ]) {
        execs[ ref ]();
      }

    })
  })

})();